﻿using System;
using System.Collections.Generic;
using System.Text;

namespace FySystem.Net.SimSocket.Protocals
{
    internal class MsgHandlerV1 : HandlerBase
    {
        /// <summary>
        /// 创建客户端->服务端的握手回应包
        /// </summary>
        /// <returns></returns>
        internal override byte[] GenHelloCSPackage(byte[] byteGuid, ushort version)
        {
            List<byte> res = new List<byte>();
            try
            {
                byte[] byteMask = new byte[16];
                byte[] byteRes = new byte[16];

                //随机掩码
                Random random = new Random(BitConverter.ToInt32(byteGuid, 0));
                random.NextBytes(byteMask);

                //将GUID和掩码进行异或
                for (int i = 0; i < 16; i++)
                    byteRes[i] = (byte)(byteGuid[i] ^ byteMask[i]);

                res.Add(0x20);
                res.Add(0x08);
                res.AddRange(byteGuid);
                res.AddRange(byteMask);
                res.AddRange(byteRes);
                res.Add((byte)(version & 0xFF));
            }
            catch (Exception)
            {
                throw;
            }
            return res.ToArray();
        }

        /// <summary>
        /// 校验握手数据包
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="bytesRead"></param>
        /// <param name="helloInfo"></param>
        /// <returns></returns>
        internal override bool ValidateHello(ref byte[] buffer, int bytesRead, ref HelloInfo helloInfo)
        {
            bool res = false;
            try
            {
                if (buffer == null)
                    return false;
                if (bytesRead < 51)
                    return false;
                if (buffer[0] != 0x20 && buffer[1] != 0x08)
                    return false;

                //16字节的GUID
                byte[] byteGuid = new byte[16];
                StringBuilder sb = new StringBuilder(32);
                for (int i = 2; i <= 17; i++)
                {
                    byteGuid[i - 2] = buffer[i];
                    sb.Append(buffer[i].ToString("X2"));
                }
                helloInfo.Guid = sb.ToString();

                //18字节的随机掩码
                byte[] byteMask = new byte[16];
                for (int i = 18; i <= 33; i++)
                    byteMask[i - 18] = buffer[i];

                //传过来的计算结果
                byte[] byteOriResult = new byte[16];
                for (int i = 34; i <= 49; i++)
                    byteOriResult[i - 34] = buffer[i];

                //自己计算结果
                byte[] byteResult = new byte[16];
                for (int i = 0; i < 16; i++)
                    byteResult[i] = (byte)(byteGuid[i] ^ byteMask[i]);

                //结果比较
                res = true;
                for (int i = 0; i < 16; i++)
                {
                    if (byteResult[i] != byteOriResult[i])
                    {
                        res = false;
                        break;
                    }
                }
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 创建服务端->客户端的握手回应包
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        internal override byte[] GenHelloSCPackage(ref byte[] buffer, bool valResult)
        {
            byte[] res = new byte[3];
            try
            {
                res[0] = 0x20;
                res[1] = 0x08;
                res[2] = (byte)(valResult == true ? 0x01 : 0x00);
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 校验握手回复数据包
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="bytesRead"></param>
        /// <returns></returns>
        internal override bool ValidateHelloReply(ref byte[] buffer, int bytesRead)
        {
            bool res = false;
            try
            {
                if (buffer == null)
                    return res;
                if (bytesRead != 3)
                    return res;

                if (buffer[0] == 0x20 && buffer[1] == 0x08 && buffer[2] == 0x01)
                    res = true;
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 解析包
        /// </summary>
        /// <param name="stateObjectBase"></param>
        /// <param name="bytesRead"></param>
        /// <returns></returns>
        internal override List<FrameInfo> DepackFrame(SimStateObjectBase stateObjectBase, int bytesRead)
        {
            List<FrameInfo> res = null;
            try
            {
                Span<byte> span = new Span<byte>(stateObjectBase.buffer, 0, bytesRead);
                stateObjectBase.stream.AddRange(span.ToArray());

                if (stateObjectBase.stream.Count < 2)
                    return null;

                while (stateObjectBase.stream.Count >= 2)
                {
                    int index = 0;
                    FrameInfo frameInfo = new FrameInfo();

                    //FIN
                    if ((stateObjectBase.stream[index] & 0x80) == 0)                    //二进制的1000 0000等于0x80，如果最高位是1，与运算后为0x80，如果最高位是0，与运算后是0
                        frameInfo.IsFinished = false;
                    else if ((stateObjectBase.stream[index] & 0x80) == 0x80)
                        frameInfo.IsFinished = true;

                    //opcode
                    int opcode = stateObjectBase.stream[index] & 0x0F;
                    frameInfo.PackType = (EPackTypes)opcode;

                    //Payload length
                    index += 1;
                    int payload = stateObjectBase.stream[index];
                    if (payload == 126)
                    {
                        index += 1;
                        byte[] bytes = new byte[2];
                        bytes[0] = stateObjectBase.stream[index];
                        bytes[1] = stateObjectBase.stream[index + 1];
                        payload = BitConverter.ToUInt16(bytes);
                        index += 2;
                    }
                    else if (payload == 127)
                    {
                        //这个只是预留，消息长度不可能那么长，后续也不好处理，所以目前一帧数据的最大长度是int的最大值
                        //这里不太确定有没有bug，之前按照8字节来解析的，但看打包的代码应该只有4字节
                        index += 1;
                        //byte[] bytes = new byte[8];
                        //for (int i = 0; i < 8; i++)
                        //    bytes[i] = stateObjectBase.buffer[index + i];
                        byte[] bytes = new byte[4];
                        for (int i = 0; i < 4; i++)
                            bytes[i] = stateObjectBase.stream[index + i];
                        payload = BitConverter.ToInt32(bytes);
                        index += 4;
                    }
                    else
                        index += 1;

                    //获取数据
                    if (index + payload > stateObjectBase.stream.Count)
                        break;

                    if (payload > 0)
                    {
                        res = res == null ? new List<FrameInfo>() : res;
                        frameInfo.Frame = new byte[payload];
                        for (int i = 0; i < payload; i++)
                            frameInfo.Frame[i] = stateObjectBase.stream[i + index];

                        res.Add(frameInfo);
                        stateObjectBase.stream.RemoveRange(0, index + payload);
                    }
                    else
                    {
                        res = res == null ? new List<FrameInfo>() : res;
                        frameInfo.Frame = null;
                        res.Add(frameInfo);
                        stateObjectBase.stream.RemoveRange(0, index);
                    }
                }
            }
            catch (Exception)
            {
                //throw;
            }
            return res;
        }

        /// <summary>
        /// 生成ping数据包
        /// </summary>
        /// <returns></returns>
        internal override byte[] GenPingPackage()
        {
            byte[] res = null;
            try
            {
                res = PackFrame(new PackInfo()
                {
                    Data = null,
                    IsFinish = true,
                    OpCode = 0x01
                });
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 生成pong数据包
        /// </summary>
        /// <returns></returns>
        internal override byte[] GenPongPackage()
        {
            byte[] res = null;
            try
            {
                res = PackFrame(new PackInfo()
                {
                    Data = null,
                    IsFinish = true,
                    OpCode = 0x02
                });
            }
            catch (Exception)
            {
                throw;
            }
            return res;
        }

        /// <summary>
        /// 数据打包
        /// </summary>
        /// <param name="packInfo"></param>
        /// <returns></returns>
        internal override byte[] PackFrame(PackInfo packInfo)
        {
            List<byte> res = new List<byte>();
            try
            {
                if (packInfo == null)
                    return null;

                //第一字节
                byte b = packInfo.OpCode;
                if(packInfo.IsFinish==true)
                    b = (byte)(packInfo.OpCode | 0x80);    //0x80是1000 0000
                res.Add(b);

                //payload length
                int length = packInfo.Data == null ? 0 : packInfo.Data.Length;
                if (length <= 125)
                {
                    res.Add((byte)length);
                }
                else
                {
                    if (length <= ushort.MaxValue)
                    {
                        res.Add(126);
                        byte[] bl = BitConverter.GetBytes((ushort)length);
                        res.AddRange(bl);
                    }
                    else
                    {
                        res.Add(127);
                        byte[] bl = BitConverter.GetBytes(length);
                        res.AddRange(bl);
                    }
                }

                if (packInfo.Data != null)
                    res.AddRange(packInfo.Data);
            }
            catch (Exception)
            {
                throw;
            }
            return res.ToArray();
        }

        internal override byte[] PackFrame(ref byte[] data)
        {
            List<byte> res = new List<byte>(data.Length);
            try
            {
                //第一字节
                byte b = 0 | 0x80;
                res.Add(b);

                //payload length
                int length = data == null ? 0 : data.Length;
                if (length <= 125)
                {
                    res.Add((byte)length);
                }
                else
                {
                    if (length <= ushort.MaxValue)
                    {
                        res.Add(126);
                        byte[] bl = BitConverter.GetBytes((ushort)length);
                        res.AddRange(bl);
                    }
                    else
                    {
                        res.Add(127);
                        byte[] bl = BitConverter.GetBytes(length);
                        res.AddRange(bl);
                    }
                }

                if (data != null)
                    res.AddRange(data);
            }
            catch (Exception)
            {
                throw;
            }
            return res.ToArray();
        }

        internal override byte[] PackFrame(List<byte> data)
        {
            List<byte> res = new List<byte>(data.Count + 5);
            try
            {
                //第一字节
                byte b = 0 | 0x80;
                res.Add(b);

                //payload length
                int length = data == null ? 0 : data.Count;
                if (length <= 125)
                {
                    res.Add((byte)length);
                }
                else
                {
                    if (length <= ushort.MaxValue)
                    {
                        res.Add(126);
                        byte[] bl = BitConverter.GetBytes((ushort)length);
                        res.AddRange(bl);
                    }
                    else
                    {
                        res.Add(127);
                        byte[] bl = BitConverter.GetBytes(length);
                        res.AddRange(bl);
                    }
                }

                if (data != null)
                    res.AddRange(data);
            }
            catch (Exception)
            {
                throw;
            }
            return res.ToArray();
        }
    }
}
